/* ---------------------------------------------------------------------------
 *
 * Copyright (c) Doug Weems.
 * 
 * You may use this code for fun and knowledge.
 * You can compile and use the application as is or copy out what you need.  
 * This code makes for a really useful tool.
 * 
 * ---------------------------------------------------------------------------
 */

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Drawing.Imaging;
using SHDocVw;
using mshtml;


namespace IEWindowCapture
{
	/// <summary>
	/// This is the working code for "IE Complete Web Window Image Capture".  IECWWIC for short.  
	/// Just kidding. ;-)  Call it, "WebPageToImage".
	/// This tool will pick up one open IE window and capture the entire web page to a single jpeg.
	/// It is best if you only are running the IE instance that you are interested in.
	/// The quality and size of the image can be adjusted and standard resolution screen sizes and web page name
	/// can be added to the image.
	/// Author:  Doug Weems
	/// </summary>
	public class frmMain : System.Windows.Forms.Form
	{
        private System.Windows.Forms.GroupBox grpWebCapture;
        private System.Windows.Forms.LinkLabel lnkOpenCapture;
        private System.Windows.Forms.CheckBox chkShowGuides;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.ComboBox cmbResolution;
        private System.Windows.Forms.Label lblResolution;
        private System.Windows.Forms.Label lblQuality;
        private System.Windows.Forms.ComboBox cmbQuality;
        private System.Windows.Forms.CheckBox chkWriteURL;
        private System.Windows.Forms.Button button1;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;



		public frmMain()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(frmMain));
            this.grpWebCapture = new System.Windows.Forms.GroupBox();
            this.lnkOpenCapture = new System.Windows.Forms.LinkLabel();
            this.chkShowGuides = new System.Windows.Forms.CheckBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.cmbResolution = new System.Windows.Forms.ComboBox();
            this.lblResolution = new System.Windows.Forms.Label();
            this.lblQuality = new System.Windows.Forms.Label();
            this.cmbQuality = new System.Windows.Forms.ComboBox();
            this.chkWriteURL = new System.Windows.Forms.CheckBox();
            this.button1 = new System.Windows.Forms.Button();
            this.grpWebCapture.SuspendLayout();
            this.groupBox1.SuspendLayout();
            this.SuspendLayout();
            // 
            // grpWebCapture
            // 
            this.grpWebCapture.Controls.Add(this.lnkOpenCapture);
            this.grpWebCapture.Controls.Add(this.chkShowGuides);
            this.grpWebCapture.Controls.Add(this.groupBox1);
            this.grpWebCapture.Controls.Add(this.chkWriteURL);
            this.grpWebCapture.Controls.Add(this.button1);
            this.grpWebCapture.Location = new System.Drawing.Point(28, 12);
            this.grpWebCapture.Name = "grpWebCapture";
            this.grpWebCapture.Size = new System.Drawing.Size(256, 208);
            this.grpWebCapture.TabIndex = 41;
            this.grpWebCapture.TabStop = false;
            this.grpWebCapture.Text = "Capture Web Page";
            // 
            // lnkOpenCapture
            // 
            this.lnkOpenCapture.Location = new System.Drawing.Point(16, 136);
            this.lnkOpenCapture.Name = "lnkOpenCapture";
            this.lnkOpenCapture.Size = new System.Drawing.Size(128, 16);
            this.lnkOpenCapture.TabIndex = 36;
            this.lnkOpenCapture.TabStop = true;
            this.lnkOpenCapture.Text = "Open Capture Directory";
            this.lnkOpenCapture.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkOpenCapture_LinkClicked);
            // 
            // chkShowGuides
            // 
            this.chkShowGuides.Location = new System.Drawing.Point(16, 112);
            this.chkShowGuides.Name = "chkShowGuides";
            this.chkShowGuides.Size = new System.Drawing.Size(200, 16);
            this.chkShowGuides.TabIndex = 34;
            this.chkShowGuides.Text = "draw Standard Resolution Guides";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.cmbResolution);
            this.groupBox1.Controls.Add(this.lblResolution);
            this.groupBox1.Controls.Add(this.lblQuality);
            this.groupBox1.Controls.Add(this.cmbQuality);
            this.groupBox1.ForeColor = System.Drawing.Color.Black;
            this.groupBox1.Location = new System.Drawing.Point(16, 16);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(200, 80);
            this.groupBox1.TabIndex = 39;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Reduce File Size by reducing Quality and/or Resolution";
            // 
            // cmbResolution
            // 
            this.cmbResolution.Items.AddRange(new object[] {
                                                               "100",
                                                               "90",
                                                               "80",
                                                               "70",
                                                               "60",
                                                               "50",
                                                               "40"});
            this.cmbResolution.Location = new System.Drawing.Point(120, 32);
            this.cmbResolution.Name = "cmbResolution";
            this.cmbResolution.Size = new System.Drawing.Size(48, 21);
            this.cmbResolution.TabIndex = 31;
            this.cmbResolution.Text = "90";
            // 
            // lblResolution
            // 
            this.lblResolution.Location = new System.Drawing.Point(24, 32);
            this.lblResolution.Name = "lblResolution";
            this.lblResolution.Size = new System.Drawing.Size(88, 16);
            this.lblResolution.TabIndex = 35;
            this.lblResolution.Text = "% Capture Size";
            this.lblResolution.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // lblQuality
            // 
            this.lblQuality.Location = new System.Drawing.Point(24, 56);
            this.lblQuality.Name = "lblQuality";
            this.lblQuality.Size = new System.Drawing.Size(88, 16);
            this.lblQuality.TabIndex = 38;
            this.lblQuality.Text = "Quality";
            this.lblQuality.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // cmbQuality
            // 
            this.cmbQuality.Items.AddRange(new object[] {
                                                            "100",
                                                            "90",
                                                            "80",
                                                            "70",
                                                            "50",
                                                            "30",
                                                            "10"});
            this.cmbQuality.Location = new System.Drawing.Point(120, 56);
            this.cmbQuality.Name = "cmbQuality";
            this.cmbQuality.Size = new System.Drawing.Size(48, 21);
            this.cmbQuality.TabIndex = 37;
            this.cmbQuality.Text = "70";
            // 
            // chkWriteURL
            // 
            this.chkWriteURL.Location = new System.Drawing.Point(16, 96);
            this.chkWriteURL.Name = "chkWriteURL";
            this.chkWriteURL.Size = new System.Drawing.Size(176, 16);
            this.chkWriteURL.TabIndex = 32;
            this.chkWriteURL.Text = "write URL name on Image";
            // 
            // button1
            // 
            this.button1.Cursor = System.Windows.Forms.Cursors.Hand;
            this.button1.ForeColor = System.Drawing.Color.White;
            this.button1.Image = ((System.Drawing.Image)(resources.GetObject("button1.Image")));
            this.button1.Location = new System.Drawing.Point(176, 144);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(48, 40);
            this.button1.TabIndex = 29;
            this.button1.TextAlign = System.Drawing.ContentAlignment.TopCenter;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // frmMain
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(304, 238);
            this.Controls.Add(this.grpWebCapture);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Name = "frmMain";
            this.Text = "Capture";
            this.grpWebCapture.ResumeLayout(false);
            this.groupBox1.ResumeLayout(false);
            this.ResumeLayout(false);

        }
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new frmMain());
		}


        //We need some system dll functions.
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
        public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/, IntPtr next /*HWND*/, string sClassName, IntPtr sWindowTitle);
        
        [DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)] 
        public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd); 

        [DllImport("user32.Dll")]
        public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);

        [DllImport("user32.dll")]
        private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

        public const int GW_CHILD = 5; 
        public const int GW_HWNDNEXT = 2;

        private void button1_Click(object sender, System.EventArgs e)
        {
            //TODO In Next Version:
            //Add cursor capture
            //Add file naming option
            //Add visible screen capture
            //Make captured image a DDB not a DIB bitmap.
            
            Cursor.Current = Cursors.WaitCursor;
        
            SHDocVw.WebBrowser m_browser = null;

            SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass();
 
            //Find first availble browser window.
            //Application can easily be modified to loop through and capture all open windows.
            string filename;
            foreach (SHDocVw.WebBrowser ie in shellWindows)
            {
                filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
    
                if (filename.Equals("iexplore"))
                {
                    m_browser = ie;
                    break;  
                }
            }
            if (m_browser == null)
            {   
                MessageBox.Show("No Browser Open");
                return;
            }

            //Assign Browser Document
            mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document;

            
            //URL Location
            string myLocalLink = myDoc.url;
            int URLExtraHeight = 0;
            int URLExtraLeft = 0;

            //Adjustment variable for capture size.
            if (chkWriteURL.Checked == true)
                URLExtraHeight = 25;

            //TrimHeight and TrimLeft trims off some captured IE graphics.
            int trimHeight = 3;
            int trimLeft = 3;

            //Use UrlExtra height to carry trimHeight.
            URLExtraHeight = URLExtraHeight - trimHeight;
            URLExtraLeft = URLExtraLeft - trimLeft;

            myDoc.body.setAttribute("scroll", "yes", 0);

            //Get Browser Window Height
            int heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
            int widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
            
            //Get Screen Height
            int screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
            int screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);

            //Get bitmap to hold screen fragment.
            Bitmap bm = new Bitmap(screenWidth, screenHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);

            //Create a target bitmap to draw into.
            Bitmap bm2 = new Bitmap(widthsize + URLExtraLeft, heightsize + URLExtraHeight - trimHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
            Graphics g2 = Graphics.FromImage(bm2);

            Graphics g = null;
            IntPtr hdc;
            Image screenfrag = null;
            int brwTop = 0;
            int brwLeft = 0;
            int myPage = 0;
            IntPtr myIntptr = (IntPtr)m_browser.HWND;
            //Get inner browser window.
            int hwndInt = myIntptr.ToInt32();
            IntPtr hwnd = myIntptr;
            hwnd = GetWindow(hwnd, GW_CHILD); 
            StringBuilder sbc = new StringBuilder(256);
            //Get Browser "Document" Handle
            while (hwndInt != 0) 
            { 
                hwndInt = hwnd.ToInt32();
                GetClassName(hwndInt, sbc, 256);

                if(sbc.ToString().IndexOf("Shell DocObject View", 0) > -1)
                {
                    hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
                    break;
                }                
                hwnd = GetWindow(hwnd, GW_HWNDNEXT);

            } 
            
            //Get Screen Height (for bottom up screen drawing)
            while ((myPage * screenHeight) < heightsize)
            {
                myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
                ++myPage;
            }
            //Rollback the page count by one
            --myPage;
            
            int myPageWidth = 0;

            while ((myPageWidth * screenWidth) < widthsize)
            {
                myDoc.body.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
                brwLeft = (int)myDoc.body.getAttribute("scrollLeft", 0);
                for (int i = myPage; i >= 0; --i)
                {
                    //Shoot visible window
                    g = Graphics.FromImage(bm);
                    hdc = g.GetHdc();
                    myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
                    brwTop = (int)myDoc.body.getAttribute("scrollTop", 0);
                    PrintWindow(hwnd, hdc, 0);
                    g.ReleaseHdc(hdc);
                    g.Flush();
                    screenfrag = Image.FromHbitmap(bm.GetHbitmap());
                    g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
                }
                ++myPageWidth;
            }

            //Draw Standard Resolution Guides
            if(chkShowGuides.Checked == true)
            {
                // Create pen.
                int myWidth = 1;
                Pen myPen = new Pen(Color.Navy, myWidth);
                Pen myShadowPen = new Pen(Color.NavajoWhite, myWidth);
                // Create coordinates of points that define line.
                float x1 = -(float)myWidth - 1 + URLExtraLeft;
                float y1 = -(float)myWidth - 1 + URLExtraHeight;

                float x600 = 600.0F + (float)myWidth+1;
                float y480 = 480.0F + (float)myWidth+1;

                float x2 = 800.0F + (float)myWidth+1;
                float y2 = 600.0F + (float)myWidth+1;

                float x3 = 1024.0F + (float)myWidth+1;
                float y3 = 768.0F + (float)myWidth+1;

                float x1280 = 1280.0F + (float)myWidth+1;
                float y1024 = 1024.0F + (float)myWidth+1;

                // Draw line to screen.
                g2.DrawRectangle(myPen, x1, y1, x600+myWidth, y480+myWidth);
                g2.DrawRectangle(myPen, x1, y1, x2+myWidth, y2+myWidth);
                g2.DrawRectangle(myPen, x1, y1, x3+myWidth, y3+myWidth);
                g2.DrawRectangle(myPen, x1, y1, x1280+myWidth, y1024+myWidth);

                // Create font and brush.
                Font drawFont = new Font("Arial", 12);
                SolidBrush drawBrush = new SolidBrush(Color.Navy);
                SolidBrush drawBrush2 = new SolidBrush(Color.NavajoWhite);
                
                // Set format of string.
                StringFormat drawFormat = new StringFormat();
                drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
                // Draw string to screen.
                g2.DrawString("600 x 480", drawFont, drawBrush, 5, y480 - 20 + URLExtraHeight, drawFormat);
                g2.DrawString("800 x 600", drawFont, drawBrush, 5, y2 - 20 + URLExtraHeight, drawFormat);
                g2.DrawString("1024 x 768", drawFont, drawBrush, 5, y3 - 20 + URLExtraHeight, drawFormat);
                g2.DrawString("1280 x 1024", drawFont, drawBrush, 5, y1024 - 20 + URLExtraHeight, drawFormat);
            }

            //Write URL
            if (chkWriteURL.Checked == true)
            {   //Backfill URL paint location
                SolidBrush whiteBrush = new SolidBrush(Color.White);
                Rectangle fillRect = new Rectangle(0, 0, widthsize, URLExtraHeight+2);
                Region fillRegion = new Region(fillRect);
                g2.FillRegion(whiteBrush, fillRegion);

                SolidBrush drawBrushURL = new SolidBrush(Color.Black);
                Font drawFont = new Font("Arial", 12);
                StringFormat drawFormat = new StringFormat();
                drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;

                g2.DrawString(myLocalLink, drawFont, drawBrushURL, 0, 0, drawFormat);
            }
            
            //Reduce Resolution Size
            double myResolution = Convert.ToDouble(cmbResolution.Text) * 0.01;
            int finalWidth = (int)((widthsize + URLExtraLeft) * myResolution);
            int finalHeight = (int)((heightsize + URLExtraHeight) * myResolution);
            Bitmap finalImage = new Bitmap(finalWidth, finalHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
            Graphics gFinal = Graphics.FromImage((Image)finalImage);
            gFinal.DrawImage( bm2, 0, 0, finalWidth, finalHeight);
  
            //Get Time Stamp
            DateTime myTime = DateTime.Now;
            String format = "MM.dd.hh.mm.ss";

            //Create Directory to save image to.
            Directory.CreateDirectory("C:\\IECapture");

            //Write Image.
            EncoderParameters eps = new EncoderParameters(1);
            long myQuality = Convert.ToInt64(cmbQuality.Text);
            eps.Param[0] = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, myQuality);
            ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
            finalImage.Save(@"c:\\IECapture\Captured_" + myTime.ToString(format) + ".jpg", ici, eps);


            //Clean Up.
            myDoc = null;
            g.Dispose();
            g2.Dispose();
            gFinal.Dispose();
            bm.Dispose();
            bm2.Dispose();
            finalImage.Dispose();

            Cursor.Current = Cursors.Default;
        }

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for(j = 0; j < encoders.Length; ++j)
            {
                if(encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        private void lnkOpenCapture_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("explorer.exe", "C:\\IECapture");
        }



	}
}
